package com.esun.rabbit2.communicaters.recharg;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;


/** 
* @ClassName: DataPackageBuilder 
* @Description: 数据包组织类，该类实现了数据包的组织
* @author Miko baoz@500wan.com
* @date 2011-1-13 下午09:40:01 
*  
*/
abstract class DataPackageBuilder {

	// head2 + body 长度，初始只是head2长度，因为body长度还未知
	private int intBodyLength = DataShare.SECONDHEADLENGTH;

	// 验证字段 数值为 body部分所有数字的总和
	private int wChecksum;

	// 业务编号。
	private short wMFuncNo;
	
	// 压缩方式
	private byte compress;
	
	// 加密方式
	private byte encrypt;
	
	private String sessionId;
	
	private byte[] head1,head2,body;

//	static byte[] body;

	// 初始化工具类
	// private ByteUtils byteUtils = new ByteUtils();

	private String strBody;

	
	/**
	 * @param strBody 获得String类型的包体
	 * @param wMFuncNo 获得业务编号
	 * @param compress 获得压缩方式
	 * @param encrypt 获得加密方式
	 * @param userSession 用户会话SessionId
	 * 
	 * @author Miko
	 */
	public DataPackageBuilder(String userSession,String strBody, short wMFuncNo, byte compress,
			byte encrypt) {
		this.strBody = strBody;
		this.wMFuncNo = wMFuncNo;
		this.compress = compress;
		this.encrypt = encrypt;
		this.sessionId = userSession;
		buildBody();
		buildSecondHead();
//		buildFirstHead();
		
	}

	/**
	 * 构建byte[] head1
	 * 
	 * @author Miko
	 */
	private void buildFirstHead() {

		head1 = new byte[DataShare.FIRSTHEADLENGTH];

		// byte数组标识位 从0开始
		int position = 0;
		
		// 添加协议版本号
		ByteUtils.integer2Bytes(head1, position, DataShare.PROTOCOLVERSION);
		
		// 标识位向后移4位
		position += 4;

		// 添加终端标识
		ByteUtils.shortToBytes(head1, position, DataShare.K_AN);
		
		// 标识位向后移2位
		position += 2;

		// 添加包长度（head2 + body）
		ByteUtils.integer2Bytes(head1, position, this.intBodyLength);
		
		// 标识位向后移4位
		position += 4;

		// 添加压缩方式
		head1[position] = this.compress;
		
		// 标识位向后移1位
		position += 1;

		// 添加加密方式
		head1[position] = this.encrypt;
		
		// 标识位向后移1位
		position += 1;

		// 添加验证字段（body部分数据合）
		ByteUtils.integer2Bytes(head1, position, this.wChecksum);
		// 标识位向后移4位
		position += 4;
		
		
		ByteUtils.shortToBytes(head1, position, DataShare.TIME_STAMP);
		
		
//		EDebug.o(this,"-------------------------------------------------------------------------------------------------- ");
//		EDebug.o(this,"head 1 is ");
//		
//		for(int i=0;i<head1.length;i++){
//		    EDebug.o(this,"head1["+i+"] => [" +head1[i] + "]");
//		}
		
		
	}

	/**
	 * 构建byte[] head2
	 * @author Miko
	 */
	private void buildSecondHead() {

		head2 = new byte[DataShare.SECONDHEADLENGTH];

		// byte数组标识位 从0开始
		int position = 0;

		ByteUtils.StringToBytes(DataShare.QWUSERID, head2, position);
		
		// 标识位向后移40位
		position += 40;

		ByteUtils.StringToBytes(sessionId, head2, position);
		
		// 标识位向后移100位
		position += 100;

		ByteUtils.shortToBytes(head2, position, DataShare.WPLATYPE);
		
		// 标识位向后移2位
		position += 2;

		ByteUtils.shortToBytes(head2, position, this.wMFuncNo);
		
		// 标识位向后移2位
		position += 2;

		head2[position] = DataShare.WSTATUS;
		
		// 标识位向后移1位
		position += 1;

		ByteUtils.integer2Bytes(head2, position, DataShare.DOWNLOADNUM);
		
//		EDebug.o(this,"-------------------------------------------------------------------------------------------------- ");
//        EDebug.o(this,"head 2 is ");
//        
//        for(int i=0;i<head2.length;i++){
//            EDebug.o(this,"head2["+i+"] => [" +head2[i] + "]");
//        }
//        EDebug.o(this,"-------------------------------------------------------------------------------------------------- ");
	}
	
	
	/**
	 * <p>构建byte[] body</p>
	 * <p>将传入的String字符串安 " " 分开，并转换为binary字符串</p>
	 * <p>需要将" "转换成binary形式，添加到字符串中，若直接转译" "可能会出错或引起接续错误</p>
	 * @author Miko
	 */
	private void buildBody(){
		
		try {
			
			String[] strBodyTemp = strBody.split(" ");
			
			// 以流形式转换
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			
			for(int i=0;i<strBodyTemp.length;i++){
				try {
					baos.write(strBodyTemp[i].getBytes("UTF-8"));
					baos.write(0);
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			
			String preBody = baos.toString();
			body = preBody.getBytes("UTF-8");
			
			// 获取包体总长
			intBodyLength += body.length;
			
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	
	
	/**
	 * 构建 完整需要发送的 byte[]
	 * 
	 * @return postData 得到的最终需要想server发送的数据包
	 * @author Miko
	 */
	public byte[] getDataPackage(){
		
		// 需要获得校验字部分的byte[]（被检查部分）
		byte[] checkedData = new byte[DataShare.SECONDHEADLENGTH + body.length ];
		
		// 将head2放入待查byte[]中
		System.arraycopy(head2, 0, checkedData, 0, DataShare.SECONDHEADLENGTH);
		
		// 将body放入待查byte[]中,并和head2拼装在一起
		System.arraycopy(body, 0, checkedData, DataShare.SECONDHEADLENGTH, body.length);
		
		this.wChecksum = getChecksum(checkedData);
		
		// 因为head1部分信息需要得到head2 和 body部分的信息，所以在这里创建
		buildFirstHead();
		
		
		// 整体包的长度
		int strPackageLength = head1.length + head2.length + body.length;
		
		// 包 组织完全的的缓存区域
		byte[] postData = new byte[strPackageLength];
		
		
		// 将head1放入待发byte[]中。
		System.arraycopy(head1, 0, postData, 0, DataShare.FIRSTHEADLENGTH);
		
		// 将checkedData放入待发byte[]中，并和head1拼装成一个完整的数据包
		System.arraycopy(checkedData, 0, postData,DataShare.FIRSTHEADLENGTH , DataShare.SECONDHEADLENGTH + body.length);
		
		return postData;
	}

	
	
	/**
	 * 获得数据包的校验字
	 * 
	 * @param byt
	 *            需要计算的byte数组
	 * @return checkSumReturn 所有byte数组内数字想加的总和即校验字
	 * @author Miko
	 */
	private final static int getChecksum(byte[] byt) {
		int checkSumReturn = 0;
		int dwLen = byt.length;
		/*
		 * for (int i = 0; i < dwLen / 2; i++) { wRet +=
		 * KUtils.bytes2Short(data, i * 2); }
		 */
		for (int i = 0; i < dwLen; i++) {
			checkSumReturn += byt[i];
		}
		/*
		 * if (dwLen % 2 > 0) { byte[] tmp = new byte[2]; tmp[0] = 0; tmp[1] =
		 * data[dwLen - 1]; wRet += KUtils.bytes2Short(tmp, 0); }
		 */
		return checkSumReturn;
	}
	
	

}
